package cn.org.guhao.practice.go.juc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * CompletableFutureDemo
 *
 * @author guhao
 * @since 2020/5/8
 */
public class CompletableFutureDemo {

  private static final Logger logger = LoggerFactory.getLogger(CompletableFutureDemo.class);

  public static List<String> runAsync() {
    long start = System.currentTimeMillis();
    //结果集
    List<String> result = new ArrayList<>();
    //定长10线程池
    ExecutorService exs = Executors.newFixedThreadPool(10);
    List<CompletableFuture<String>> futureList = new ArrayList<>();

    final List<Integer> taskList = Arrays.asList(2,1,3,4,5,6,7,8,9,10);
    try {
      // 推荐方式：全流式处理转换成CompletableFuture[]+组装成一个无返回值CompletableFuture，join等待执行完毕。返回结果whenComplete获取
      CompletableFuture[] cfs = taskList.stream().map(object-> CompletableFuture.supplyAsync(()->calc(object), exs)
          .thenApply(h->Integer.toString(h))
          //如需获取任务完成先后顺序，此处代码即可
          .whenComplete((v, e) -> {
            if(e != null) {
              logger.error("发生异常", e);
            }
            logger.info("任务[{}]完成!result=[{}],[{}]", v,v,LocalDateTime.now());
            result.add(v);
          })).toArray(CompletableFuture[]::new);
      //等待总任务完成，但是封装后无返回值，必须自己whenComplete()获取
      CompletableFuture.allOf(cfs).join();
      logger.info("任务完成先后顺序，结果:[{}];耗时:[{}]", result,(System.currentTimeMillis()-start));
    } catch (Exception e) {
      logger.error("执行发生异常", e);
    }finally {
      exs.shutdown();
    }
    return result;
  }

  private static Integer calc(Integer i){
    try {
      if(i==1){
        //任务1耗时3秒
        Thread.sleep(3000);
      }else if(i==5){
        //任务5耗时5秒
        Thread.sleep(5000);
      }else{
        //其它任务耗时1秒
        Thread.sleep(1000);
      }
      logger.info("task线程：[{}],任务[{}]完成！[{}]", Thread.currentThread().getName(),i, LocalDateTime.now());
    } catch (InterruptedException e) {
      logger.error("执行被中断", e);
    }
    return i;
  }

}
